package cn.iocoder.yudao.module.agent.service.brokeragewithdrawrecord;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.module.agent.controller.app.brokeragewithdrawrecord.vo.AppAgentBrokerageWithdrawRecordCreateReqVO;
import cn.iocoder.yudao.module.agent.dal.dataobject.user.AgentUserDO;
import cn.iocoder.yudao.module.agent.dal.dataobject.withdrawaccount.AgentWithdrawAccountDO;
import cn.iocoder.yudao.module.agent.enums.AgentBrokerageRecordBizTypeEnum;
import cn.iocoder.yudao.module.agent.enums.AgentBrokerageRecordStatusEnum;
import cn.iocoder.yudao.module.agent.enums.AgentBrokerageWithdrawStatusEnum;
import cn.iocoder.yudao.module.agent.enums.NotifyMessageTemplateConstants;
import cn.iocoder.yudao.module.agent.service.brokeragerecord.AgentBrokerageRecordService;
import cn.iocoder.yudao.module.agent.service.user.AgentUserService;
import cn.iocoder.yudao.module.agent.service.withdrawaccount.AgentWithdrawAccountService;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.sms.SmsSendApi;
import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleToUserReqDTO;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;
import cn.iocoder.yudao.module.agent.controller.admin.brokeragewithdrawrecord.vo.*;
import cn.iocoder.yudao.module.agent.dal.dataobject.brokeragewithdrawrecord.AgentBrokerageWithdrawRecordDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

import cn.iocoder.yudao.module.agent.convert.brokeragewithdrawrecord.AgentBrokerageWithdrawRecordConvert;
import cn.iocoder.yudao.module.agent.dal.mysql.brokeragewithdrawrecord.AgentBrokerageWithdrawRecordMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.agent.enums.ErrorCodeConstants.*;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;

/**
 * 代理人佣金提现记录 Service 实现类
 *
 * @author 曹建伟
 */
@Service
@Validated
public class AgentBrokerageWithdrawRecordServiceImpl implements AgentBrokerageWithdrawRecordService {

    @Resource
    private AgentBrokerageWithdrawRecordMapper brokerageWithdrawRecordMapper;

    @Resource
    private AgentUserService agentUserService;

    @Resource
    private AgentWithdrawAccountService agentWithdrawAccountService;

    @Resource
    private AgentBrokerageRecordService agentBrokerageRecordService;

    @Resource
    private SmsSendApi smsSendApi;

    @Resource
    private MemberUserApi memberUserApi;

    @Override
    public Long createBrokerageWithdrawRecord(AgentBrokerageWithdrawRecordCreateReqVO createReqVO) {
        // 插入
        AgentBrokerageWithdrawRecordDO brokerageWithdrawRecord = AgentBrokerageWithdrawRecordConvert.INSTANCE.convert(createReqVO);
        brokerageWithdrawRecordMapper.insert(brokerageWithdrawRecord);
        // 返回
        return brokerageWithdrawRecord.getId();
    }

    @Override
    public void updateBrokerageWithdrawRecord(AgentBrokerageWithdrawRecordUpdateReqVO updateReqVO) {
        // 校验存在
        validateBrokerageWithdrawRecordExists(updateReqVO.getId());
        // 更新
        AgentBrokerageWithdrawRecordDO updateObj = AgentBrokerageWithdrawRecordConvert.INSTANCE.convert(updateReqVO);
        brokerageWithdrawRecordMapper.updateById(updateObj);
    }

    @Override
    public void deleteBrokerageWithdrawRecord(Long id) {
        // 校验存在
        validateBrokerageWithdrawRecordExists(id);
        // 删除
        brokerageWithdrawRecordMapper.deleteById(id);
    }

    private AgentBrokerageWithdrawRecordDO validateBrokerageWithdrawRecordExists(Long id) {
        AgentBrokerageWithdrawRecordDO withdrawRecordDO =brokerageWithdrawRecordMapper.selectById(id);
        if (withdrawRecordDO == null) {
            throw exception(BROKERAGE_WITHDRAW_RECORD_NOT_EXISTS);
        }

        return withdrawRecordDO;
    }

    @Override
    public AgentBrokerageWithdrawRecordDO getBrokerageWithdrawRecord(Long id) {
        return brokerageWithdrawRecordMapper.selectById(id);
    }

    @Override
    public List<AgentBrokerageWithdrawRecordDO> getBrokerageWithdrawRecordList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return ListUtil.empty();
        }
        return brokerageWithdrawRecordMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<AgentBrokerageWithdrawRecordDO> getBrokerageWithdrawRecordPage(AgentBrokerageWithdrawRecordPageReqVO pageReqVO) {
        return brokerageWithdrawRecordMapper.selectPage(pageReqVO);
    }

    @Override
    public List<AgentBrokerageWithdrawRecordDO> getBrokerageWithdrawRecordList(AgentBrokerageWithdrawRecordExportReqVO exportReqVO) {
        return brokerageWithdrawRecordMapper.selectList(exportReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long appCreateBrokerageWithdrawRecord(AppAgentBrokerageWithdrawRecordCreateReqVO createReqVO){
        AgentUserDO agentUserDO = agentUserService.getByUserId(createReqVO.getUserId());
        if(agentUserDO == null){
            throw exception(USER_NOT_EXISTS);
        }

        if(!agentUserDO.getEnabled()){
            throw exception(AGENT_NOT_ENABLED);
        }

        AgentWithdrawAccountDO accountDO = agentWithdrawAccountService.getWithdrawAccount(agentUserDO.getWithdrawId());
        if(accountDO == null){
            throw exception(WITHDRAW_ACCOUNT_NOT_EXISTS);
        }

        if(agentUserDO.getBrokerage() < createReqVO.getPrice()){
            throw exception(BROKERAGE_NOT_ENOUGH);
        }

        // 1. 计算手续费 todo
        int feePrice = 0;

        // 2. 创建提现记录
        AgentBrokerageWithdrawRecordDO brokerageWithdrawRecordDO = AgentBrokerageWithdrawRecordConvert.INSTANCE.convert(agentUserDO, accountDO, createReqVO, feePrice);
        brokerageWithdrawRecordMapper.insert(brokerageWithdrawRecordDO);

        // 3. 创建用户佣金记录
        agentBrokerageRecordService.reduceBrokerage(agentUserDO.getUserId(),
                AgentBrokerageRecordBizTypeEnum.WITHDRAW,
                brokerageWithdrawRecordDO.getId(),
                brokerageWithdrawRecordDO.getPrice(),
                AgentBrokerageRecordBizTypeEnum.WITHDRAW.getTitle());

        return brokerageWithdrawRecordDO.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditBrokerageWithdraw(Long id, AgentBrokerageWithdrawStatusEnum status, String auditReason){
        // 1.1校验存在
        AgentBrokerageWithdrawRecordDO withdrawRecordDO = validateBrokerageWithdrawRecordExists(id);

        AgentUserDO agentUserDO = agentUserService.getByUserId(withdrawRecordDO.getUserId());
        if(agentUserDO == null){
            throw exception(USER_NOT_EXISTS);
        }

        AgentWithdrawAccountDO withdrawAccountDO = agentWithdrawAccountService.getWithdrawAccount(agentUserDO.getWithdrawId());
        if(withdrawAccountDO == null){
            throw exception(BROKERAGE_ACCOUNT_NOT_EXISTS);
        }

        // 1.2 校验状态为审核中
        if (ObjectUtil.notEqual(AgentBrokerageWithdrawStatusEnum.AUDITING.getStatus(), withdrawRecordDO.getStatus())) {
            throw exception(BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING);
        }

        // 2. 更新
        int rows = brokerageWithdrawRecordMapper.updateByIdAndStatus(id, AgentBrokerageWithdrawStatusEnum.AUDITING.getStatus(),
                new AgentBrokerageWithdrawRecordDO().setStatus(status.getStatus()).setAuditReason(auditReason).setAuditTime(LocalDateTime.now()));
        if (rows == 0) {
            throw exception(BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING);
        }

        String templateCode = null;
        if (AgentBrokerageWithdrawStatusEnum.AUDIT_SUCCESS.equals(status)) {
            // 3.1 审核通过
            //线下转账
            templateCode = NotifyMessageTemplateConstants.AGENT_BROKERAGE_WITHDRAW_APPROVE;
            agentUserService.addWithdrawBrokerage(agentUserDO.getUserId(), withdrawRecordDO.getPrice());
        }else if(AgentBrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)){
            // 3.1 审核不通过
            // 因为提交申请的时候已经扣除佣金，审核失败需要返还
            templateCode = NotifyMessageTemplateConstants.AGENT_BROKERAGE_WITHDRAW_REJECT;
            agentBrokerageRecordService.addBrokerage(agentUserDO.getUserId(),
                    AgentBrokerageRecordBizTypeEnum.WITHDRAW_REJECT,
                    withdrawRecordDO.getId(),
                    withdrawRecordDO.getPrice(),
                    AgentBrokerageRecordBizTypeEnum.WITHDRAW_REJECT.getTitle());
        }

        MemberUserRespDTO memberUserDTO = memberUserApi.getUser(agentUserDO.getUserId());
        if(memberUserDTO == null){
            throw exception(USER_NOT_EXISTS);
        }

        // 4 通知用户
        SmsSendSingleToUserReqDTO smsDTO = new SmsSendSingleToUserReqDTO();
        smsDTO.setUserId(agentUserDO.getUserId());
        smsDTO.setMobile(memberUserDTO.getMobile());
        smsDTO.setTemplateCode(templateCode);
        Map<String, Object> templateParams = MapUtil.<String, Object>builder()
                .put("createTime", LocalDateTimeUtil.formatNormal(withdrawRecordDO.getCreateTime()))
                .put("price", MoneyUtils.fenToYuanStr(withdrawRecordDO.getPrice()))
                .put("reason", auditReason)
                .build();
        smsDTO.setTemplateParams(templateParams);

        smsSendApi.sendSingleSmsToMember(smsDTO);
    }

}
